#include "TCPInterface.h"


#include <unistd.h>
#include <stdarg.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include "SysLog.h"


// If the size of the buffer is too large, will take more than 1 time to send by TCP
int SendDataByTCP(int sockfd, const void *buf, size_t len, int flags)
{
    NETWORK_COMM_STU sendCommStu;
    char *p = (char *)buf;
    char sendBuf[1024];
    
    int nTime = (len / 1024);
    int successRet = 0;
    int ret = 0;

    // not the last time
    for(; nTime > 0; nTime--)
    {
        // printf("************* nTime = [%d] **************\n", nTime);
        memset(&sendCommStu, 0, sizeof(sendCommStu));
        memcpy(sendCommStu.cStrDataBuff, p, sizeof(sendCommStu.cStrDataBuff));
        sendCommStu.nSize = sizeof(sendCommStu.cStrDataBuff);
        sendCommStu.bLastFlag = false;

        ret = send(sockfd, (char *)&sendCommStu, sizeof(sendCommStu), flags);
        successRet += ret;
        p +=ret;

        usleep(5000);
    }

    // last time
    memset(&sendCommStu, 0, sizeof(sendCommStu));
    memcpy(sendCommStu.cStrDataBuff, p, len - successRet);
    sendCommStu.nSize = len - successRet;
    sendCommStu.bLastFlag = true;

    // maybe the size is a bug
    ret = send(sockfd, (char *)&sendCommStu, sizeof(sendCommStu), flags);
    successRet += ret;


    return successRet;
    
}

// Recv Data by TCP, can handle the many times situation.
int RecvDataByTCP(int sockfd, std::string &strRecvBuf, int flags)
{
    int nSuccessRet = 0;
    std::string strTmpRecvBuf;
    
    NETWORK_COMM_STU recvCommStu;
    memset(&recvCommStu, 0, sizeof(recvCommStu));

    // When there is a large amount of data, will recv many time.
    // so need to flag the last time to over the recv process
    while(true)
    {
        char recvBuf[MAX_COMM_SIZE];
        int ret = recv(sockfd, recvBuf, MAX_COMM_SIZE, flags);

        memset(&recvCommStu, 0, sizeof(recvCommStu));
        memcpy(&recvCommStu, recvBuf, sizeof(recvCommStu));

        // append each time's data
        strTmpRecvBuf += recvCommStu.cStrDataBuff;
        nSuccessRet += ret;

        // last frame in this communication?
        if (recvCommStu.bLastFlag == true)
        {
            break;
        }
    }

    strRecvBuf = strTmpRecvBuf;

    return nSuccessRet;
}


int SocketInitTCPServer(const char* cstrIp, int port)
{
    //================socket()
    int fd = socket(AF_INET, SOCK_STREAM, 0);
    if (fd == -1)
    {
        printf("socket error\n");
        return -1;
    }

    // 设置端口复用 ( bind error 发生这种情况是在服务端主动关闭连接以后，接着立即启动就会出现这种错误)
    int opt = 1;
    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int));

    // 定义一个结构体来存放服务器（本机）的信息，用于bind()
    struct sockaddr_in ipAddr;
    memset(&ipAddr, 0, sizeof(ipAddr));

    ipAddr.sin_family = AF_INET;                // 协议
    ipAddr.sin_port = htons(port);              // 端口号
    ipAddr.sin_addr.s_addr = inet_addr(cstrIp); // 本机的IP地址

    //================bind()
    int ret = bind(fd, (struct sockaddr *)&ipAddr, sizeof(ipAddr));
    if (ret == -1)
    {
        printf("bind error\n");
        return -1;
    }

    //================listen()
    ret = listen(fd, 0);
    if (ret == -1)
    {
        printf("bind error\n");
        return -1;
    }

    return fd;
}

int SocketInitTCPClient()
{
    //================socket()
    int fd = socket(AF_INET, SOCK_STREAM, 0);
    if (fd == -1)
    {
        printf("socket error\n");
        return -1;
    }

    printf("SocketInitTCPClient() return fd = %d\n", fd);
    return fd;

}